package com.heima.user.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.heima.common.exception.CustException;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.user.dtos.LoginCodeDTO;
import com.heima.model.user.pojos.ApUser;
import com.heima.model.user.pojos.ApUserErrorCode;
import com.heima.user.mapper.ApUserMapper;
import com.heima.user.service.ApUserCodeLoginService;
import com.heima.user.utils.IpUtil;
import com.heima.utils.common.AppJwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
@Slf4j
public class ApUserCodeLoginServiceImpl implements ApUserCodeLoginService {
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    ApUserMapper apUserMapper;
    @Autowired
    HttpServletRequest request;

    @Override
    public ResponseResult verificationCodeLogin(LoginCodeDTO dto){
        // 检查参数  先判断  手机号+验证码是否为空  手机号是否合法
        if(StringUtils.isNotBlank(dto.getPhone())&&StringUtils.isNotBlank(dto.getVerificationCode())){
            // 检查手机号是否合法
            String reg = "^[1][358][0-9]{9}$";
            Pattern pattern = Pattern.compile(reg);
            Matcher matcher = pattern.matcher(dto.getPhone());
            boolean booleanTel = matcher.matches();
            if (!booleanTel){
                log.info("手机号码不合法");
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_ALLOW,"您的手机号码不合法");
            }
            //从request中获取用户登陆ip
            String ip = IpUtil.getIpAddr(request);
            String blackList = dto.getPhone() + "_" + ip;
            String ipPhone = ip + "_" +  dto.getPhone();
            //1.判断是否当前用户是否在黑名单中
            ValueOperations<String, String> opeBlackList = redisTemplate.opsForValue();
            if(opeBlackList.get(blackList) != null){
                log.info("用户在黑名单中，稍后重新登陆");
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_ALLOW,"您在黑名单中，请稍后重新输入");
            }
            // 2 先用手机号查询用户
            // 2.1  判断当前用户是否存在
            ApUser apUser = apUserMapper.selectOne(Wrappers.<ApUser>lambdaQuery().eq(ApUser::getPhone, dto.getPhone()));
            if (apUser==null) {
                log.info("用户未注册");
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST,"用户未注册");
            }
            //2.2判断当前用户是否被冻结
            if(apUser.getStatus()){
                log.info("登陆失败，原因是用户已被冻结");
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_ALLOW,"您已经被冻结，请联系管理员激活");
            }
            ValueOperations<String, String> opeVerificationCode = redisTemplate.opsForValue();
            String code = opeVerificationCode.get(dto.getPhone() + "smCode");
            if(code == null){
                log.info("登陆时未先获取验证码");
                return ResponseResult.okResult("请重新获取验证码");
            }
            //判断输入的验证码和redis中的是否一致
            if(dto.getVerificationCode().equals(code)){
                // 2.3  一致  颁发token  返回结果:  user    token
                String token = AppJwtUtil.getToken(Long.valueOf(apUser.getId()));
                Map result = new HashMap<>();
                apUser.setPassword("");
                apUser.setSalt("");
                result.put("user",apUser);
                result.put("token",token);
                log.info("用户登陆成功");
                List<String> list = Arrays.asList(dto.getPhone() + "smCode", ipPhone, blackList);
                redisTemplate.delete(list);
                return ResponseResult.okResult(result);
            }
            //3.验证码和redis中的不一致
            else {
                //从redis中获取ApUserErrorCode数据
                ValueOperations<String, String> opeCodeAndCycle = redisTemplate.opsForValue();
                String codeAndCycle = opeCodeAndCycle.get(ipPhone);
                //3.1如果是第一次输入验证码错误
                if(codeAndCycle == null){
                    ApUserErrorCode apUserErrorCode = new ApUserErrorCode();
                    apUserErrorCode.setCount(1);
                    apUserErrorCode.setCycleThreeCode(0);
                    String stringApUserCode = JSON.toJSONString(apUserErrorCode);
                    opeCodeAndCycle.set(ipPhone,stringApUserCode);
                    log.info("第一次输入验证码错误");
                    return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_ALLOW,"请重新输入验证码");
                }
                ApUserErrorCode apUserErrorCode = JSON.parseObject(codeAndCycle, ApUserErrorCode.class);
                //判断输入验证码错误是否达到3次
                if( apUserErrorCode.getCount() !=  3 ){
                    //3.2没达到3次
                    apUserErrorCode.setCount(apUserErrorCode.getCount()+1);
                    String stringApUserCode = JSON.toJSONString(apUserErrorCode);
                    opeCodeAndCycle.set(ipPhone,stringApUserCode);
                    log.info("第一次输入验证码错误，没达到3次");
                    return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_ALLOW,"请重新输入验证码");
                }else{
                    //3.4第二次输入验证码错误达到3次
                    if (apUserErrorCode.getCycleThreeCode() == 1){
                        apUser.setStatus(true);
                        apUserMapper.updateById(apUser);
                        List<String> list = Arrays.asList(dto.getPhone() + "smCode", ipPhone, blackList);
                        redisTemplate.delete(list);
                        ResponseResult<Object> responseResult = new ResponseResult<>();
                        responseResult.setData(apUser.getId());
                        responseResult.setErrorMessage("您已经被冻结，请联系管理员激活");
                        log.info("第二次输入验证码错误达到3次");
                        return responseResult;
                    }
                    //3.3如果第一次输入验证码错误达到3次  将错误次数归零 同时将CycleThreeCode设置为1 表示已经有了一次输入3次错误的验证码
                    apUserErrorCode.setCount(0);
                    apUserErrorCode.setCycleThreeCode(1);
                    String stringApUserCode = JSON.toJSONString(apUserErrorCode);
                    opeCodeAndCycle.set(ipPhone,stringApUserCode);
                    opeBlackList.set(blackList,"forbid",1, TimeUnit.MINUTES);
                    log.info("第一次输入验证码错误达到3次");
                    return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_ALLOW,"验证码输入错误次数过多，请五分钟重试");
                }

                }
            }
        //用设备id登陆
        else {
            if(dto.getEquipmentId() == null){
                CustException.cust(AppHttpCodeEnum.PARAM_INVALID,"手机号 或 设备id不能为空");
            }
            // 3. 如果手机号 或 密码为空 那么使用设备id登录
            String token = AppJwtUtil.getToken(0L);
            // 3.1  直接颁发token 存储的用户id 0
            Map result = new HashMap<>();
            result.put("token",token);
            log.info("设备id登陆成功");
            return ResponseResult.okResult(result);
        }
    }
    }
